﻿using DeepZoomPivotConstructor.DTBuilderLib;
using DeepZoomPivotConstructor.VisualCacheInterfaces;
using DeepZoomPivotConstructor.VisualLib;
using DeepZoomPivotConstructor.VisualLib.Hotspots;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace t_DTBuilderLib
{
    /// <summary>
    /// Summary description for t_ZeepZoomBuilder
    /// </summary>
    [TestClass]
    public class t_DeepZoomBuilder
    {
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        [TestInitialize]
        public void Setup()
        {
            Environment.CurrentDirectory = TestContext.DeploymentDirectory;
        }

        [TestMethod]
        public void DeepZoomBuilderCTor()
        {
            DeepZoomBuilder dz = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
        }

        [TestMethod]
        public async Task DeepZoomRenderSimpleImage()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\DeepZoomRenderSimpleImage");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, bm);

            d.Refresh();
            Assert.IsTrue(d.Exists, "Output directory does not exist!");
            Assert.IsTrue(File.Exists(d.FullName + "\\DeepZoomRenderSimpleImage.xml"), "Output xml file does not exist");
        }

        [TestMethod]
        public async Task TestRenderEmptyImage()
        {
            VisualHolder empty = new VisualHolder();
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestRenderEmptyImage");
            await bld.RenderVisual(d, empty);
        }

        [TestMethod]
        public async Task RenderWithSpace()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\Render With Space");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, bm);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");
            Assert.IsTrue(File.Exists(d.FullName + "\\Render With Space.xml"), "Output xml file does not exist");
        }

        [TestMethod]
        public async Task TestRenderNullImage()
        {
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestRenderNullImage");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, null);
        }

        [TestMethod]
        public async Task DeepZoomRenderCrash()
        {
            bool madeit = true;
            try
            {
                VisualBitmapImage bm = new VisualBitmapImage(1.0F, 1.0F, 16000, Color.Red);
                DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
                await bld.RenderVisual(new DirectoryInfo(".\\DeepZoomRenderCrash"), bm);
            }
            catch
            {
                madeit = false;
            }
            Assert.IsFalse(madeit, "SparseImageTool did not crash - can't complete test!");
        }

        [TestMethod]
        public async Task TestRenderVisualsAsCollections()
        {
            DirectoryInfo curDir = new DirectoryInfo(".\\TestRenderVisualsAsCollections");
            DirectoryInfo imageDir = new DirectoryInfo(curDir.FullName + "\\images");

            if (!imageDir.Exists)
            {
                imageDir.Create();
            }

            VisualHolder master = new VisualHolder();
            int NsubRenders = 3;
            for (int i = 0; i < NsubRenders; i++)
            {
                VisualHolder h = new VisualHolder();
                for (int j = 0; j < 3; j++)
                {
                    VisualBitmapImage b = new VisualBitmapImage(1.0, 1.0, 600, Color.Red);
                    b.ImageWritingDirectory = imageDir;
                    b.XPosition = j * 1.1;
                    h.AddImage(b);
                }

                h.XPosition = i * 4.5;
                h.SetAsComposableUnit(curDir); /// Fake it out - fine for this test?
                h.Info = new Visual.VisualInfo();
                h.Info.Title = "Really Darn Bogus";
                master.AddImage(h);
            }
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            await bld.RenderVisual(curDir, master);

            ///
            /// Now, see if the sub-token files are there! We expect one per rendering.
            /// 

            DirectoryInfo subRenderings = new DirectoryInfo(curDir.FullName + @"\sc");
            Assert.IsTrue(subRenderings.Exists, "Expected directory not there!?");
            var xmlFiles = from f in subRenderings.GetFiles()
                           where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                           select f;

            Assert.AreEqual(NsubRenders, xmlFiles.Count(), "Wrong number of sub-rendering xml files found!");

            //
            // Is the real meeting data there?
            //

            var fout = new FileInfo(string.Format(@"{0}\{1}.xml", curDir.FullName, curDir.Name));
            Assert.IsTrue(fout.Exists, "Main meetin XML file is missing");
            using (var rdr = fout.OpenText())
            {
                var full = rdr.ReadToEnd();
                var r = new Regex("\"sc/");
                var m = r.Matches(full);
                Assert.AreEqual(3, m.Count, "# of times sc appears");
            }

            ///
            /// Is the meeting meta data thing there?
            /// 

            Assert.IsTrue(File.Exists(curDir.FullName + "\\meetingMetadata.xml"), "Meeting meta data is missing");
        }

        class CacheDB : IVisualCacheDB
        {
            /// <summary>
            /// Should be able to ignore this one...
            /// </summary>
            /// <param name="hash"></param>
            /// <returns></returns>
            public CacheDBInfo FindHit(long hash)
            {
                throw new NotImplementedException();
            }

            public CacheDBInfo SavedCacheLine { get; set; }

            public long Hash { get; set; }

            public void Save(CacheDBInfo info)
            {
                Hash = info.ComposeInfo.Hash;
                SavedCacheLine = info;
            }

        }

        [TestMethod]
        public async Task TestSaveCU()
        {
            ///
            /// Test that a CU causes a DB update.
            /// 

            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);

            bm.SetAsComposableUnit(DateTime.Now);
            bm.CompositionInfo.RenderObject = new FileInfo("junk.jpg");
            bm.CompositionInfo.Hash = (bm.CompositionInfo.RenderObject as FileInfo).FullName.GetHashCode();
            bm.CompositionInfo.Width = 2.0;
            bm.CompositionInfo.Height = 3.0;
            bm.CompositionInfo.RenderItemFullType = "bleah";

            bm.Info = new Visual.VisualInfo();
            bm.Info.Title = "This is a slide";

            CacheDB db = new CacheDB();
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger(), db);

            DirectoryInfo d = new DirectoryInfo(".\\TestSaveCU");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, bm);

            Assert.IsNotNull(db.SavedCacheLine, "Saved cache line should not be null");
            Assert.AreEqual(new FileInfo("junk.jpg").FullName.GetHashCode(), db.Hash, "Hash isn't set correctl");
            Assert.AreEqual(2.0, db.SavedCacheLine.ComposeInfo.Width, "Width isn't right");
            Assert.IsNotNull(db.SavedCacheLine.DZXMLFile, "File for xml file should not be null!");
            Assert.IsTrue(db.SavedCacheLine.DZXMLFile.Exists, "XML file should exist on disk!");
        }

        [TestMethod]
        public async Task TestNumberOfSubImageCounter()
        {
            ///
            /// Run a rendering, which saves a file for output!
            /// 

            CacheDB db = new CacheDB();
            var result = await RunRender("TestRecallSavedCU", db);

            var dz = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            Assert.AreEqual(1, dz.NumberOfSubImages(result), "Incorrect number of sub-images found!");
        }

        [TestMethod]
        public async Task TestRecallSavedCU()
        {
            ///
            /// Run a rendering, which saves a file for output!
            /// 

            CacheDB db = new CacheDB();
            await RunRender("TestRecallSavedCU", db);

            ///
            /// make sure the right number of sub images exist down there...
            /// 

            DirectoryInfo d = new DirectoryInfo(@".\TestRecallSavedCU");
            FileInfo subimageDir = null;
            DirectoryInfo dsub = new DirectoryInfo(d.FullName + @"\sc");
            {
                var dirfiles = from f in dsub.GetFiles()
                               where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                               select f;
                Assert.AreEqual(1, dirfiles.Count(), "Wrong number of sub rendering xml files");
                subimageDir = dirfiles.First();
            }

            ///
            /// A compositon unit has already been rendered. We make sure that DZComposer recovers
            /// it correctly!
            /// 

            Visual.VisualInfo info = new Visual.VisualInfo();
            info.Title = "hi";
            VisualItemPlaceHolder place = new VisualItemPlaceHolder(db.SavedCacheLine.ComposeInfo.Width,
                db.SavedCacheLine.ComposeInfo.Height,
                db.SavedCacheLine.DZXMLFile,
                info, this);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());

            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, place);

            ///
            /// after rendering expected no new sub-images!
            /// 

            {
                d.Refresh();
                var dirfiles = from f in dsub.GetFiles()
                               where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                               select f;
                Assert.AreEqual(1, dirfiles.Count(), "Wrong number of sub rendering xml files after second rendering");
                FileInfo newSubImageDir = dirfiles.First();
                Assert.AreEqual(subimageDir.FullName, newSubImageDir.FullName, "THe sub image name should be the same!");
            }
        }

        [TestMethod]
        public async Task TestCUOneLevelDown()
        {
            ///
            /// Run a rendering, which saves a file for output!
            /// 

            CacheDB db = new CacheDB();
            await RunRenderCUOneLevelDown("TestCUOneLevelDown", db);

            ///
            /// make sure the right number of sub images exist down there...
            /// 

            DirectoryInfo d = new DirectoryInfo(@".\TestCUOneLevelDown");
            FileInfo[] subimageDir = null;
            DirectoryInfo dsub = new DirectoryInfo(d.FullName + @"\sc");
            {
                var dirfiles = from f in dsub.GetFiles()
                               where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                               select f;
                Assert.AreEqual(2, dirfiles.Count(), "Wrong number of sub rendering xml files");
                subimageDir = dirfiles.ToArray();
            }

            ///
            /// A compositon unit has already been rendered. We make sure that DZComposer recovers
            /// it correctly!
            /// 

            Visual.VisualInfo info = new Visual.VisualInfo();
            info.Title = "hi";
            VisualItemPlaceHolder place = new VisualItemPlaceHolder(db.SavedCacheLine.ComposeInfo.Width,
                db.SavedCacheLine.ComposeInfo.Height,
                db.SavedCacheLine.DZXMLFile,
                info,
                this);

            Visual h = BuildVisualOneLevelUp(place);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());

            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);

            ///
            /// after rendering expected no new sub-images!
            /// 

            {
                d.Refresh();
                dsub.Refresh();
                var dirfiles = from f in dsub.GetFiles()
                               where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                               select f;
                Assert.AreEqual(2, dirfiles.Count(), "Wrong number of sub rendering xml files after second rendering");
                FileInfo[] newSubImageDir = dirfiles.ToArray();

                var matching = from f1 in newSubImageDir
                               from f2 in subimageDir
                               where f1.FullName == f2.FullName
                               select f1;

                Assert.AreEqual(1, matching.Count(), "Expected one stable sub image - didn't seem to find it!");
            }
        }

        /// <summary>
        /// Runs a render with a CU, but the CU is one level down, and includes an extra bit map compared
        /// to the normal RunRender method below.
        /// </summary>
        /// <param name="renderDirName"></param>
        /// <param name="db"></param>
        private async Task RunRenderCUOneLevelDown(string renderDirName, CacheDB db)
        {
            ///
            /// Test that a CU causes a DB update.
            /// 

            VisualBitmapImage bm = BuildCUBitmapImage();

            VisualHolder h = BuildVisualOneLevelUp(bm);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger(), db);

            DirectoryInfo d = new DirectoryInfo(".\\" + renderDirName);
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);
        }

        private static VisualHolder BuildVisualOneLevelUp(Visual bm)
        {
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            VisualBitmapImage bs1 = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Green);
            bs1.XPosition = 11.0;
            h.AddImage(bs1);
            return h;
        }

        private static VisualBitmapImage BuildCUBitmapImage()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);

            bm.SetAsComposableUnit(DateTime.Now);
            bm.CompositionInfo.RenderObject = new FileInfo("junk.jpg");
            bm.CompositionInfo.Hash = (bm.CompositionInfo.RenderObject as FileInfo).FullName.GetHashCode();
            bm.CompositionInfo.Width = 2.0;
            bm.CompositionInfo.Height = 3.0;
            bm.CompositionInfo.RenderItemFullType = "bleah";

            bm.Info = new Visual.VisualInfo();
            bm.Info.Title = "This is a slide";
            return bm;
        }

        /// <summary>
        /// Runs a render against a database.
        /// </summary>
        /// <param name="p"></param>
        private async Task<DirectoryInfo> RunRender(string renderDirName, CacheDB db)
        {
            ///
            /// Test that a CU causes a DB update.
            /// 

            VisualBitmapImage bm = BuildCUBitmapImage();

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger(), db);

            DirectoryInfo d = new DirectoryInfo(".\\" + renderDirName);
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, bm);
            d.Refresh();
            return d;
        }

        [TestMethod]
        public async Task TestMetaDataSaved()
        {
            /// Make sure that a comp-unit's meta data is correctly saved

            CacheDB db = new CacheDB();
            await RunRender("TestMetaDataSaved", db);
            Assert.IsNotNull(db.SavedCacheLine.Metadata, "Meta data should not be null!");
            Assert.IsNotNull(db.SavedCacheLine.Metadata.Title, "Title should not be null!");
            Assert.AreEqual("This is a slide", db.SavedCacheLine.Metadata.Title, "Title is not correct");
        }

        [TestMethod]
        public async Task TestUnusedDirectoriesDeleted()
        {
            ///
            /// When sub meeting is rendered, and we don't use some (old??) sub meeting directories,
            /// make sure they get deleted!
            /// 

            DirectoryInfo curDir = new DirectoryInfo(".\\TestUnusedDirectoriesDeleted");
            DirectoryInfo imageDir = new DirectoryInfo(curDir.FullName + "\\images");

            if (!imageDir.Exists)
            {
                imageDir.Create();
            }

            VisualHolder master = new VisualHolder();
            int NsubRenders = 3;
            for (int i = 0; i < NsubRenders; i++)
            {
                VisualHolder h = new VisualHolder();
                for (int j = 0; j < 3; j++)
                {
                    VisualBitmapImage b = new VisualBitmapImage(1.0, 1.0, 600, Color.Red);
                    b.ImageWritingDirectory = imageDir;
                    b.XPosition = j * 1.1;
                    h.AddImage(b);
                }

                h.XPosition = i * 4.5;
                h.SetAsComposableUnit(curDir); /// Fake it out - fine for this test?
                h.Info = new Visual.VisualInfo();
                h.Info.Title = "Really Darn Bogus";
                master.AddImage(h);
            }
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            await bld.RenderVisual(curDir, master);

            ///
            /// Now, see if the sub-token files are there! We expect one per rendering.
            /// 

            DirectoryInfo subRenderings = new DirectoryInfo(curDir.FullName + @"\sc");
            Assert.IsTrue(subRenderings.Exists, "Expected directory not there!?");
            var xmlFiles = from f in subRenderings.GetDirectories()
                           select f;

            Assert.AreEqual(NsubRenders, xmlFiles.Count(), "Wrong number of sub-rendering directories found!");

            ///
            /// Run the render again... while we might have new sub-renders, we shouldn't
            /// have any different # of directories.
            /// 

            await bld.RenderVisual(curDir, master);
            subRenderings.Refresh();
            Assert.IsTrue(subRenderings.Exists, "Expected directory not there!?");
            var xmldir2 = from f in subRenderings.GetDirectories()
                          select f;

            Assert.AreEqual(NsubRenders, xmldir2.Count(), "Wrong number of re-sub-rendering directories found!");

            var xmlFiles2 = from f in subRenderings.GetFiles()
                            where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                            select f;

            Assert.AreEqual(3, xmlFiles2.Count(), "Expected only 3 xml files after DZC cleanup!");
        }

        [TestMethod]
        public async Task TestHSOutputFile()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com"))
            };
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            h.AddImage(vhs);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputFile");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);
            d.Refresh();

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            TestForHSFiles(d.FullName + "\\sc", 1, new int[] { 1 }, "main hs file");
        }

        [TestMethod]
        public async Task TestHSOutputWithCU()
        {
            /// The sub-image with a HS

            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com"))
            };
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            h.AddImage(vhs);
            h.SetAsComposableUnit(null, "testWithLink");

            /// The main image, which contains the above

            VisualBitmapImage bmMain = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Black);
            VisualHolder all = new VisualHolder();
            h.ScaleToWidth(1.0);
            h.XPosition = 11.0;
            all.AddImage(bmMain);
            all.AddImage(h);

            /// Render and make sure teh HS files show up!

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputWithCU");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, all);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            TestForHSFiles(d.FullName + "\\sc", 2, new int[] { 1, 0 }, "HS Files for 2 part render");
        }

        [TestMethod]
        public async Task TestHSOutputFromTitle()
        {
            /// The sub-image with a HS

            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            h.SetAsComposableUnit(null, "testWithLink");
            h.ScaleToWidth(1.0);
            h.XPosition = 11.0;

            /// The main image, which contains the above

            VisualBitmapImage bmMain = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Black);

            ///
            /// And a title for the above CU
            /// 

            var vt = new VisualTitleAndBackground(h);
            vt.Add(0.25, "fork", new HSActionLink(new Uri("http://www.nytimes.com")));

            VisualHolder all = new VisualHolder();
            all.AddImage(bmMain);
            all.AddImage(vt);

            /// Render and make sure teh HS files show up!

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputFromTitle");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, all);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            TestForHSFiles(d.FullName + "\\sc", 2, new int[] { 1, 0 }, "HS Files for 2 part render");
        }

        [TestMethod]
        public async Task TestHSAboveCU()
        {
            /// The sub-image with a HS

            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            h.SetAsComposableUnit(null, "testWithLink");
            h.ScaleToWidth(1.0);
            h.XPosition = 11.0;

            /// The main image, which contains the above and the HS.

            VisualBitmapImage bmMain = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Black);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com"))
            };
            vhs.ScaleToWidth(1.0);
            vhs.XPosition = 11.0;

            VisualHolder all = new VisualHolder();

            all.AddImage(bmMain);
            all.AddImage(h);
            all.AddImage(vhs);

            /// Render and make sure teh HS files show up!

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSAboveCU");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, all);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            TestForHSFiles(d.FullName + "\\sc", 2, new int[] { 1, 0 }, "HS Files for 2 part render");
        }

        /// <summary>
        /// Look to see if n hot spot files showed up, and test to make sure that all the numbers of HS in each one
        /// appear uniquely.
        /// </summary>
        /// <param name="p"></param>
        /// <param name="p_2"></param>
        /// <param name="p_3"></param>
        /// <param name="p_4"></param>
        private void TestForHSFiles(string directoryToSearch, int nHotspotFiles, int[] validHSValues, string someText)
        {
            ///
            /// Find all the hot spot files
            /// 

            DirectoryInfo scDir = new DirectoryInfo(directoryToSearch);
            var xmlfiles = from f in scDir.GetFiles()
                           where f.Extension == ".xml" && f.Name.Contains("HotSpotdata")
                           select f;

            Assert.AreEqual(nHotspotFiles, xmlfiles.Count(), "Incorrect number of hotspot files!");

            List<int> remainingValidValues = new List<int>(validHSValues);
            foreach (var hs in xmlfiles)
            {
                int nhs = CountNHotSpots(hs, someText);
                Trace.WriteLine("File " + hs.Name + " has " + nhs + " hot spots in it");
                Assert.IsTrue(remainingValidValues.Contains(nhs), "File with incorrect number of hot spots found (" + nhs + ") - " + someText);
                remainingValidValues.Remove(nhs);
            }
        }

        /// <summary>
        /// COunt the number of hot spots in a xml hot spot file.
        /// </summary>
        /// <param name="fin"></param>
        /// <param name="what"></param>
        /// <returns></returns>
        private static int CountNHotSpots(FileInfo fin, string what)
        {
            int count = 0;
            Assert.IsTrue(fin.Exists, "hot spot file is missing " + what);
            using (var text = fin.OpenRead())
            {
                XmlSerializer xml = new XmlSerializer(typeof(DZHotSpotMetaData[]));
                DZHotSpotMetaData[] result = xml.Deserialize(text) as DZHotSpotMetaData[];
                count = result.Length;
            }
            return count;
        }

        [TestMethod]
        public async Task TestHSOutputFileDeep()
        {
            ///
            /// Make sure hot spots put up deep in the hierarchy are correctly
            /// surfaced and written out!

            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com"))
            };
            VisualHolder h1 = new VisualHolder();
            VisualHolder h2 = new VisualHolder();
            h2.AddImage(bm);
            h2.AddImage(vhs);
            h1.AddImage(h2);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputFileDeep");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h1);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            TestForHSFiles(d.FullName + "\\sc", 1, new int[] { 1 }, "main hs file");
        }

        [TestMethod]
        public async Task TestHSOutputFileDeepCU()
        {
            ///
            /// Make sure hot spots put up deep in the hierarchy are correctly
            /// surfaced and written out!

            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com"))
            };
            VisualHolder h1 = new VisualHolder();
            VisualHolder h2 = new VisualHolder();
            h2.AddImage(bm);
            h2.AddImage(vhs);
            h1.AddImage(h2);
            h1.SetAsComposableUnit(null);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputFileDeepCU");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h1);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            TestForHSFiles(d.FullName + "\\sc", 1, new int[] { 1 }, "main comp unit file");
        }

        [TestMethod]
        public async Task TestHSLinkOutputTrue()
        {
            await TestLinkOutputTrueFalse(true);
        }

        [TestMethod]
        public async Task TestHSLinkOutputFalse()
        {
            await TestLinkOutputTrueFalse(false);
        }

        /// <summary>
        /// Run the actual test!
        /// </summary>
        private async Task TestLinkOutputTrueFalse(bool LinkValue)
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com")) {LeftClickToActivate = LinkValue}
            };
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            h.AddImage(vhs);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\" + TestContext.TestName);
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);

            DirectoryInfo scDir = new DirectoryInfo(d.FullName + "\\sc");
            var xmlfiles = from f in scDir.GetFiles()
                           where f.Extension == ".xml" && f.Name.Contains("HotSpotdata")
                           select f;
            FileInfo hsFile = xmlfiles.First();
            using (var text = hsFile.OpenRead())
            {
                XmlSerializer xml = new XmlSerializer(typeof(DZHotSpotMetaData[]));
                DZHotSpotMetaData[] result = xml.Deserialize(text) as DZHotSpotMetaData[];
                Assert.IsNotNull(result[0].Actions, "Expected one actoin, but got null");
                Assert.AreEqual(1, result[0].Actions.Count, "Expected 1 action!");
                Assert.AreEqual(LinkValue, result[0].Actions[0].LinkActivatedByLeftClick, "Link should ahve been clickable!");
            }
        }

        [TestMethod]
        public async Task TestHSKeySettings()
        {
            await RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed.ArrowLeft,
                HotSpotActionBase.ActivationKeys.KeyLeftArrow,
                3);
            await RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed.NoKey,
                HotSpotActionBase.ActivationKeys.NoKeys,
                2);
            await RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed.ArrowDown,
                HotSpotActionBase.ActivationKeys.KeyDownArrow,
                5);
            await RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed.ArrowDown | DZHotSpotMetaData.ActionData.KeyPressed.ArrowLeft,
                HotSpotActionBase.ActivationKeys.KeyDownArrow | HotSpotActionBase.ActivationKeys.KeyLeftArrow,
                6);
            await RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed.ArrowRight,
                HotSpotActionBase.ActivationKeys.KeyRightArrow,
                1);
            await RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed.ArrowUp,
                HotSpotActionBase.ActivationKeys.KeyUpArrow,
                4);
        }

        private static async Task RunKeyPressTest(DZHotSpotMetaData.ActionData.KeyPressed toRead, HotSpotActionBase.ActivationKeys toSet, int index)
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHotSpot vhs = new VisualHotSpot(11.0, 8.5)
            {
                new HSActionLink(new Uri("http://www.nytimes.com")) {KeysToActivate = toSet}
            };
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);
            h.AddImage(vhs);



            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSKeySettings" + index.ToString());
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);

            DirectoryInfo scDir = new DirectoryInfo(d.FullName + "\\sc");
            var xmlfiles = from f in scDir.GetFiles()
                           where f.Extension == ".xml" && f.Name.Contains("HotSpotdata")
                           select f;
            FileInfo hsFile = xmlfiles.First();
            using (var text = hsFile.OpenRead())
            {
                XmlSerializer xml = new XmlSerializer(typeof(DZHotSpotMetaData[]));
                DZHotSpotMetaData[] result = xml.Deserialize(text) as DZHotSpotMetaData[];
                Assert.AreEqual((int)toRead, result[0].Actions[0].LinkActivatedByKeys, "Expected key settings not found");
            }
        }

        [TestMethod]
        public async Task TestHSOutputFileWithNoHS()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputFileWithNoHS");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);
            d.Refresh();

            Assert.IsTrue(d.Exists, "Output directory does not exist!");
            TestForHSFiles(d.FullName + "\\sc", 1, new int[] { 0 }, "main hs file");
        }


        [TestMethod]
        public async Task TestHSOutputFileInComposite()
        {
            VisualBitmapImage bm1 = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualBitmapImage bm2 = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHolder h = new VisualHolder();
            h.AddImage(bm1);
            VisualHolder subh = new VisualHolder();
            subh.AddImage(bm2);
            subh.SetAsComposableUnit(null);

            VisualHotSpot vhs1 = new VisualHotSpot(bm2.Width, 1.0)
            {
                new HSActionLink(new Uri("http://www.nytimes.com"))
            };
            subh.AddImage(vhs1);

            VisualHotSpot vhs2 = new VisualHotSpot(bm1.Width, 1.0)
            {
                new HSActionLink(new Uri("http://www.microsoft.com"))
            };
            h.AddImage(vhs2);

            h.AddImage(subh);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestHSOutputFileInComposite");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);
            d.Refresh();

            Assert.IsTrue(d.Exists, "Output directory does not exist!");

            /// Make sure we see only one link at the top level and one link at the composite image level.

            TestForHSFiles(d.FullName + "\\sc", 2, new int[] { 1, 1 }, "main hs or single sub image");
        }

        [TestMethod]
        public async Task TestNoOneSubImageForOneTopLevelImage()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualHolder h = new VisualHolder();
            h.AddImage(bm);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestNoOneSubImageForOneTopLevelImage");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);
            d.Refresh();

            Assert.IsTrue(d.Exists, "Output directory does not exist!");
            DirectoryInfo scDir = new DirectoryInfo(d.FullName + "\\sc");
            Assert.IsTrue(scDir.Exists, "sub image directory should be there!");
            Assert.AreEqual(1, scDir.GetDirectories().Count(), "Expected only one subdirectory!");
        }

        [TestMethod]
        public async Task TestOneSubImageForTwoTopLevelImage()
        {
            VisualBitmapImage bm1 = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            VisualBitmapImage bm2 = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            bm2.XPosition = 11.0;
            VisualHolder h = new VisualHolder();
            h.AddImage(bm1);
            h.AddImage(bm2);

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestOneSubImageForTwoTopLevelImage");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, h);
            d.Refresh();

            Assert.IsTrue(d.Exists, "Output directory does not exist!");
            DirectoryInfo scDir = new DirectoryInfo(d.FullName + "\\sc");
            Assert.IsTrue(scDir.Exists, "sub image directory should be there!");
            Assert.AreEqual(1, scDir.GetDirectories().Count(), "Expected only one subdirectory!");
        }

        [TestMethod]
        public async Task TestDZVisualMetaData()
        {
            VisualBitmapImage bm = new VisualBitmapImage(11.0F, 8.5F, 100, Color.Red);
            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            DirectoryInfo d = new DirectoryInfo(".\\TestDZVisualMetaData");
            if (!d.Exists)
            {
                d.Create();
            }
            await bld.RenderVisual(d, bm);

            Assert.IsTrue(d.Exists, "Output directory does not exist!");
            Assert.IsTrue(File.Exists(d.FullName + "\\TestDZVisualMetaData.xml"), "Output xml file does not exist");
            using (var fs = File.OpenText(d.FullName + "\\MeetingMetadata.xml"))
            {
                XmlSerializer xml = new XmlSerializer(typeof(DZTalkVisualMetaData[]));
                DZTalkVisualMetaData[] meta = xml.Deserialize(fs) as DZTalkVisualMetaData[];
                fs.Close();

                Assert.AreEqual(1, meta.Length, "Expected meta data for just one sub image!");
                Assert.AreEqual(1.0, meta[0].Width, "Width should always be one of sub images!");
                Assert.AreEqual(1.0 * 8.5 / 11.0, meta[0].Height, "Height not scaled right!");
                Assert.AreEqual(0.0, meta[0].X, "X position of first subimage should be zero here!");
                Assert.AreEqual(0.0, meta[0].Y, "X position of first subimage should be zero here!");
                Assert.AreEqual(0, meta[0].Z, "Z index should be further back!");

                FileInfo subImageInfo = new FileInfo(d.FullName + "\\" + meta[0].RelativeName + ".xml");
                Assert.IsTrue(subImageInfo.Exists, "Could not find the sub image rendering file via realtive name: " + subImageInfo.ToString());
            }
        }

        [TestMethod]
        public async Task TestDZSubImageNamed()
        {
            DirectoryInfo curDir = new DirectoryInfo(".\\TestDZSubImageNamed");
            DirectoryInfo imageDir = new DirectoryInfo(curDir.FullName + "\\images");
            imageDir.Create();

            VisualHolder master = new VisualHolder();
            int NsubRenders = 3;
            for (int i = 0; i < NsubRenders; i++)
            {
                VisualHolder h = new VisualHolder();
                for (int j = 0; j < 3; j++)
                {
                    VisualBitmapImage b = new VisualBitmapImage(1.0, 1.0, 600, Color.Red);
                    b.ImageWritingDirectory = imageDir;
                    b.XPosition = j * 1.1;
                    h.AddImage(b);
                }

                h.XPosition = i * 4.5;
                h.SetAsComposableUnit(curDir, "image" + i.ToString()); /// Fake it out - fine for this test?
                h.Info = new Visual.VisualInfo();
                h.Info.Title = "Really Darn Bogus";
                master.AddImage(h);
            }

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            await bld.RenderVisual(curDir, master);

            ///
            /// Now, see if the sub-token files are there! We expect one per rendering.
            /// 

            DirectoryInfo subRenderings = new DirectoryInfo(curDir.FullName + @"\sc");
            Assert.IsTrue(subRenderings.Exists, "Expected directory not there!?");
            var xmlFiles = from f in subRenderings.GetFiles()
                           where f.Extension == ".xml" && !f.Name.Contains("HotSpot")
                           select f;

            Assert.IsTrue(xmlFiles.Where(f => f.Name == "image0.xml").Count() == 1, "Expected to find an image0 subimage, but didn't");
            Assert.IsTrue(xmlFiles.Where(f => f.Name == "image1.xml").Count() == 1, "Expected to find an image1 subimage, but didn't");
            Assert.IsTrue(xmlFiles.Where(f => f.Name == "image2.xml").Count() == 1, "Expected to find an image2 subimage, but didn't");
        }

        [TestMethod]
        public async Task TestDZSubImageEmpty()
        {
            DirectoryInfo curDir = new DirectoryInfo(".\\TestDZSubImageEmpty");
            DirectoryInfo imageDir = new DirectoryInfo(curDir.FullName + "\\images");
            imageDir.Create();

            VisualHolder master = new VisualHolder();
            int NsubRenders = 3;
            for (int i = 0; i < NsubRenders; i++)
            {
                VisualHolder h = new VisualHolder();

                if (i == 0)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        VisualBitmapImage b = new VisualBitmapImage(1.0, 1.0, 600, Color.Red);
                        b.ImageWritingDirectory = imageDir;
                        b.XPosition = j * 1.1;
                        h.AddImage(b);
                    }
                }

                h.XPosition = i * 4.5;
                h.SetAsComposableUnit(curDir, "image" + i.ToString()); /// Fake it out - fine for this test?
                h.Info = new Visual.VisualInfo();
                h.Info.Title = "Really Darn Bogus";
                master.AddImage(h);
            }

            master.AddImage(new VisualBitmapImage(1.0, 1.0, 100, Color.Black));

            DeepZoomBuilder bld = new DeepZoomBuilder(new t_TestingLibrary.TestLogger());
            await bld.RenderVisual(curDir, master);
        }
    }
}
